CKEDITOR.dialog.add('pbckcodeDialog', function (editor) {
    var tab_sizes = ['1', '2', '4', '8'];
    
    // CKEditor variables
    var dialog;
    var shighlighter = new PBSyntaxHighlighter(editor.settings.highlighter);
    
    // ACE variables
    var aceEditor, aceSession, whitespace;
    
    // EDITOR panel
    var editorPanel = {
        id: 'editor',
        label: editor.lang.pbckcode.editor,
        elements: [
            {
                type: 'hbox',
                children: [
                    {
                        type: 'text',
                        id: 'code-title',
                        label: editor.lang.pbckcode.codeTitle,
                        'default': '',
                        setup: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                this.setValue(element.getAttribute('data-pbcktitle'));
                            }
                        },
                        commit: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                element.setAttribute('data-pbcktitle', this.getValue());
                            }
                        },
                        onChange: function () {
                        }
                    },
                    {
                        type: 'text',
                        id: 'code-marked',
                        
                        label: editor.lang.pbckcode.codeMarked,
                        'default': '',
                        setup: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                this.setValue(element.getAttribute('data-pbckmarked'));
                            }
                        },
                        commit: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                element.setAttribute('data-pbckmarked', this.getValue());
                            }
                        },
                        onChange: function () {
                        }
                    },
                    {
                        type: 'select',
                        id: 'code-inline',
                        label: editor.lang.pbckcode.codeInline,
                        items: [['多行代码', 'false'], ['单行代码', 'true']],
                        'default': 'false',
                        setup: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                this.setValue(element.getAttribute('data-pbckinline'));
                            }
                        },
                        commit: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                element.setAttribute('data-pbckinline', this.getValue());
                            }
                        },
                        onChange: function () {
                        }
                    }
                ]
            },
            {
                type: 'hbox',
                children: [
                    {
                        type: 'select',
                        id: 'code-select',
                        
                        label: editor.lang.pbckcode.mode,
                        items: editor.settings.modes,
                        'default': editor.settings.modes[0][1],
                        setup: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                this.setValue(element.getAttribute('data-pbcklang'));
                            }
                        },
                        commit: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                element.setAttribute('data-pbcklang', this.getValue());
                            }
                        },
                        onChange: function () {
                            aceSession.setMode('ace/mode/' + this.getValue());
                        }
                    },
                    {
                        type: 'select',
                        id: 'code-theme',
                        
                        label: editor.lang.pbckcode.codeThemes,
                        items: editor.settings.code_themes,
                        'default': editor.settings.code_themes[0][1],
                        setup: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                this.setValue(element.getAttribute('data-pbckcodetheme'));
                            }
                        },
                        commit: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                element.setAttribute('data-pbckcodetheme', this.getValue());
                            }
                        },
                        onChange: function () {
                        }
                    },
                    {
                        type: 'select',
                        id: 'code-font',
                        label: editor.lang.pbckcode.codeFonts,
                        items: editor.settings.code_fonts,
                        'default': editor.settings.code_fonts[0][1],
                        setup: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                this.setValue(element.getAttribute('data-pbckcodetfont'));
                            }
                        },
                        commit: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                element.setAttribute('data-pbckcodetfont', this.getValue());
                            }
                        },
                        onChange: function () {
                        }
                    },
                    {
                        type: 'select',
                        id: 'code-tabsize-select',
                        
                        label: editor.lang.pbckcode.tabSize,
                        items: tab_sizes,
                        'default': editor.settings.tab_size,
                        setup: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                this.setValue(element.getAttribute('data-pbcktabsize'));
                            }
                        },
                        commit: function (element) {
                            if (element) {
                                element = element.getAscendant('pre', true);
                                element.setAttribute('data-pbcktabsize', this.getValue());
                            }
                        },
                        onChange: function (element) {
                            if (element) {
                                aceSession.setTabSize(this.getValue());
                            }
                        }
                    }
                ]
            },
            {
                type: 'html',
                html: '<div></div>',
                id: 'code-textarea',
                className: 'cke_pbckcode_ace',
                style: 'position: absolute; top: 190px; left: 10px; right: 10px; bottom: 50px;',
                setup: function (element) {
                    // get the value of the editor
                    var code = element.getHtml();
                    
                    // replace some regexp
                    code = code.replace(new RegExp('<br/>', 'g'), '\n')
                    .replace(new RegExp('<br>', 'g'), '\n')
                    .replace(new RegExp('&lt;', 'g'), '<')
                    .replace(new RegExp('&gt;', 'g'), '>')
                    .replace(new RegExp('&amp;', 'g'), '&')
                    .replace(new RegExp('&nbsp;', 'g'), ' ');
                    
                    aceEditor.setValue(code);
                },
                commit: function (element) {
                    element.setText(aceEditor.getValue());
                }
            }
        ]
    };
    
    // dialog code
    return {
        // Basic properties of the dialog window: title, minimum size.
        title: editor.lang.pbckcode.title,
        minWidth: 480,
        minHeight: 400,
        // Dialog window contents definition.
        contents: [
            editorPanel
        ],
        onLoad: function () {
            dialog = this;
            // we load the ACE plugin to our div
            aceEditor = ace.edit(dialog.getContentElement('editor', 'code-textarea')
            .getElement().getId());
            // save the aceEditor into the editor object for the resize event
            editor.aceEditor = aceEditor;
            
            // set default settings
            aceEditor.setTheme('ace/theme/' + editor.settings.theme);
            aceEditor.setHighlightActiveLine(true);
            aceEditor.setShowInvisibles(true);
            
            aceSession = aceEditor.getSession();
            aceSession.setMode('ace/mode/' + editor.settings.modes[0][1]);
            aceSession.setTabSize(editor.settings.tab_size);
            aceSession.setUseSoftTabs(true);
            
            // load ace extensions
            // whitespace = ace.require('ace/ext/whitespace');
        },
        onShow: function () {
            // get the selection
            var selection = editor.getSelection();
            // get the entire element
            var element = selection.getStartElement();
            
            // looking for the pre parent tag
            if (element) {
                element = element.getAscendant('pre', true);
            }
            // if there is no pre tag, it is an addition. Therefore, it is an edition
            if (!element || element.getName() !== 'pre') {
                element = new CKEDITOR.dom.element('pre');
                
                if (shighlighter.getTag() !== 'pre') {
                    element.append(new CKEDITOR.dom.element('code'));
                }
                this.insertMode = true;
            } else {
                if (shighlighter.getTag() !== 'pre') {
                    element = element.getChild(0);
                }
                this.insertMode = false;
            }
            // get the element to fill the inputs
            this.element = element;
            
            // focus on the editor
            aceEditor.focus();
            
            // we empty the editor
            aceEditor.setValue('');
            
            // we fill the inputs
            if (!this.insertMode) {
                this.setupContent(this.element);
            }
        },
        // This method is invoked once a user clicks the OK button, confirming the dialog.
        onOk: function () {
            var pre, element;
            pre = element = this.element;
            
            if (this.insertMode) {
                if (shighlighter.getTag() !== 'pre') {
                    element = this.element.getChild(0);
                }
            } else {
                pre = element.getAscendant('pre', true);
            }
            
            this.commitContent(element);
            
            // set the full class to the code tag
            shighlighter.setCls(pre.getAttribute('data-pbcklang') + ' ' + editor.settings.cls);
            
            element.setAttribute('class', shighlighter.getCls());
            
            // we add a new code tag into ckeditor editor
            if (this.insertMode) {
                editor.insertElement(pre);
            }
        }
    };
});

/*
 * Resize the ACE Editor
 */
CKEDITOR.dialog.on('resize', function (evt) {
    var AceEditor = evt.editor.aceEditor;
    if (AceEditor !== undefined) {
        AceEditor.resize();
    }
});

